package xyz.xtt.pay.service.impl;

import static xyz.xtt.pay.utils.AssertUtils.isFalse;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.client.response.AssetInfoResponse;
import xyz.xtt.exchange.client.ExchangeClient;
import xyz.xtt.exchange.response.AssetAuditResponse;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.api.enums.PayOrderStatusEnum;
import xyz.xtt.pay.constants.ErrorMessage;
import xyz.xtt.pay.dto.pay.GoodsInfo;
import xyz.xtt.pay.entity.TblPayOrder;
import xyz.xtt.pay.entity.TblPayOrderLog;
import xyz.xtt.pay.exception.ChainException;
import xyz.xtt.pay.service.IConfigService;
import xyz.xtt.pay.service.IInnerService;
import xyz.xtt.pay.service.INftOrderService;
import xyz.xtt.pay.service.IPayOrderOperator;
import xyz.xtt.pay.service.IRocketMqService;
import xyz.xtt.pay.service.ITblPayOrderLogService;
import xyz.xtt.pay.service.ITblPayOrderService;
import xyz.xtt.pay.support.PayCenterHttpService;
import xyz.xtt.pay.utils.RedisLockUtil;
import xyz.xtt.pay.vo.CreateOrderRequest;
import xyz.xtt.pay.vo.PayCallbackMessage;
import xyz.xtt.pay.vo.PayCenterArgsResponse;
import xyz.xtt.user.client.response.UserInfoResponse;

/**
 * @author dale
 * @date 2025/2/10
 **/
@Component
@Slf4j
public class PersonalMintV2PayOrderOperator implements IPayOrderOperator {
	@Autowired
	private PayCenterHttpService payCenterHttpService;
	@Autowired
	private RedisLockUtil redisLockUtil;
	@Autowired
	private ITblPayOrderService iTblPayOrderService;
	@Autowired
	private INftOrderService nftOrderService;
	@Autowired
	private ExchangeClient exchangeClient;
	@Autowired
	private IRocketMqService rocketMqService;
	@Autowired
	private ITblPayOrderLogService iTblPayOrderLogService;

	@Value("${personal.mint.order.price}")
	private String personalMintPrice;

	@Autowired
	private IConfigService iConfigService;

	@Autowired
	private IInnerService iInnerService;

	@Override
	public boolean canOperateType(PayOrderBusinessTypeEnum type) {
		return Objects.equals(PayOrderBusinessTypeEnum.PERSONAL_MINT_V2, type);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public PayCenterArgsResponse createPayOrder(UserInfoResponse tblUser, PayOrderBusinessTypeEnum orderTypeEnum, CreateOrderRequest request,
			GoodsInfo goodsInfo) {
		if (!StringUtils.isNumeric(request.getAssetAuditId())) {
			log
					.error("PersonalMintV2PayOrderOperator createPayOrder assetAuditId is not number. uid:{} param:{}", tblUser.getAppUserId(), JSONUtil
							.toJsonStr(request));
			throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
		}
		long businessRefId = Long.parseLong(request.getAssetAuditId());
		AssetAuditResponse auditRecord = iInnerService.assetAuditInfo(businessRefId);
		isFalse(Objects.equals(auditRecord.getAppUserId(), tblUser.getAppUserId()), ErrorMessage.ORDER_CREATE_FAILED);
		// 检查是否已经审核通过
//		ApiResult<AssetAuditDto> getAuditResult = iInnerService.getAuditRecord(tblUser.getAppUserId(), businessRefId);
		if (Objects.isNull(auditRecord)) {
			log
					.error("PersonalMintV2PayOrderOperator createPayOrder getAuditRecord failed. uid:{} param:{} result:{}", tblUser.getAppUserId(), JSONUtil
							.toJsonStr(request), JSONUtil.toJsonStr(auditRecord));
			throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
		}
//		AssetAuditDto auditRecord = getAuditResult.getData();
		if (Objects.isNull(auditRecord) || !Objects.equals(auditRecord.getResult(), 1) || !Objects.equals(auditRecord.getState(), 0)) {
			log
					.error("PersonalMintV2PayOrderOperator createPayOrder auditRecord not exist or not pass. uid:{} param:{} result:{}", tblUser
							.getAppUserId(), JSONUtil.toJsonStr(request), JSONUtil.toJsonStr(auditRecord));
			throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
		}

		goodsInfo.setGoodsId(String.valueOf(auditRecord.getId()));
		goodsInfo.setGoodsName("铸造：" + auditRecord.getAssetName());
		goodsInfo.setGoodsNums(request.getPurchaseAmount());
		goodsInfo.setGoodsType("0");

		// 分布式锁同步（商品+用户）
		String lockKey = String.format(RedisLockUtil.LOCK_KEY_USER_PURCHASE, tblUser.getAppUserId(), businessRefId);
		String lockValue = UUID.randomUUID().toString();
		boolean lock = false;
		try {
			lock = redisLockUtil.acquireLock(lockKey, lockValue, 1, TimeUnit.MINUTES);
			if (lock) {
				// 检查当前资产资产审核记录是否存在未支付完成订单，如果存在则返回现有订单
				TblPayOrder tblPayOrder = iTblPayOrderService.getByBusiness(orderTypeEnum, request.getAssetAuditId());
				if (Objects.nonNull(tblPayOrder) && Objects.equals(tblPayOrder.getPayStatus(), PayOrderStatusEnum.UN_PAY.getCode())) {
					goodsInfo.setGoodsPrice(tblPayOrder.getPayMoney());
					log.info("createPayOrder uid:{} current payOrder:{}", tblUser.getAppUserId(), JSONUtil.toJsonStr(tblPayOrder));
					PayCenterArgsResponse response = payCenterHttpService
							.buildCreateOrderParams(tblPayOrder, tblUser, request.getBackUrl(), (AssetInfoResponse) null);
					response.setCreateNewOrder(false);
					return response;
				}

				// 计算价格
				int realPayNum = auditRecord.getAmount() - auditRecord.getRightAmount();
				if (realPayNum == 0) {
					// 实际需要支付的数量为0
					log
							.info("PersonalMintV2PayOrderOperator createPayOrder realPayNum is 0. uid:{} param:{}", tblUser.getAppUserId(), JSONUtil
									.toJsonStr(request));
					// 直接创建支付成功的订单
					long payOrderId = nftOrderService
							.saveAutoSuccessPayOrder(PayOrderBusinessTypeEnum.PERSONAL_MINT_V2, String.valueOf(businessRefId), BigDecimal.ZERO, tblUser
									.getAppUserId());
					// 发送支付成功消息
					rocketMqService.sendPayOrderStatusChangeMsg(payOrderId);
					PayCenterArgsResponse response = new PayCenterArgsResponse();
					response.setAutoSuccessOrder(true);
					return response;
				}
				// 20250324重构，不走服务，直接读本地配置
				String priceResult = iConfigService.calculatePersonalMintPrice(realPayNum);
				if (StringUtils.isBlank(lockValue)) {
					log
							.error("PersonalMintV2PayOrderOperator createPayOrder calculatePersonalMintPrice failed. uid:{} param:{} result:{}", tblUser
									.getAppUserId(), JSONUtil.toJsonStr(request), JSONUtil.toJsonStr(priceResult));
					throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
				}
				BigDecimal price = new BigDecimal(priceResult).multiply(new BigDecimal(realPayNum));
				// 测试用户重置价格
				price = nftOrderService.testUserResetPrice(tblUser.getAppUserId(), price);
				goodsInfo.setGoodsPrice(price);
				// 创建支付订单
				TblPayOrder payOrder = nftOrderService
						.saveUnPayOrder(PayOrderBusinessTypeEnum.PERSONAL_MINT_V2, String.valueOf(businessRefId), price, tblUser.getAppUserId());

				// 插入延时取消任务
				nftOrderService.sendPayDelayMessage(payOrder);
				return payCenterHttpService.buildCreateOrderParams(payOrder, tblUser, request.getBackUrl(), (AssetInfoResponse) null);
			} else {
				log.warn("createOrder failed. acquire lock on goods and user failed. uid:{} param:{}", tblUser.getAppUserId(), JSONUtil.toJsonStr(request));
			}
		} finally {
			if (lock) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
		throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
	}

	/**
	 * 确认支付订单
	 *
	 * @param payOrder
	 * @param callbackMessage
	 * @param appUserId
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean confirmPayOrder(TblPayOrder payOrder, PayCallbackMessage callbackMessage, String appUserId) {
		// 更新支付记录
		nftOrderService.savePaySuccessRecord(payOrder, callbackMessage);

		// 发送支付成功消息
		rocketMqService.sendPayOrderStatusChangeMsg(payOrder.getPayOrderId());
		return true;
	}

	/**
	 * 取消支付订单
	 *
	 * @param payOrder
	 * @param reason
	 */
	@Override
	public void doPayCancel(TblPayOrder payOrder, String reason) {
		// 取消payOrder
		isFalse(iTblPayOrderService
				.updatePayStatus(payOrder.getPayOrderId(), PayOrderStatusEnum.UN_PAY, PayOrderStatusEnum.PAY_CANCEL), ErrorMessage.ORDER_OPERATE_FAILED);

		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.PAY_CANCEL.getCode())
				.payOrderId(payOrder.getPayOrderId())
				.createTime(System.currentTimeMillis())
				.detail(reason)
				.build();
		isFalse(iTblPayOrderLogService.save(payOrderLog), ErrorMessage.ORDER_OPERATE_FAILED);

		// 发送支付订单状态变更消息
		rocketMqService.sendPayOrderStatusChangeMsg(payOrder.getPayOrderId());
	}

	@Override
	public GoodsInfo getGoodsInfo(TblPayOrder payOrder) {
		AssetAuditResponse auditRecord = iInnerService.assetAuditInfo(Long.valueOf(payOrder.getBusinessRefId()));
		isFalse(Objects.equals(auditRecord.getAppUserId(), payOrder.getAppUserId()), ErrorMessage.ORDER_CREATE_FAILED);
		// ApiResult<AssetAuditDto> getAuditResult =
		// exchangeClient.getAuditRecord(payOrder.getAppUserId(),
		// Long.valueOf(payOrder.getBusinessRefId()));
//		AssetAuditDto auditRecord = getAuditResult.getData();
		GoodsInfo goodsInfo = new GoodsInfo();
		goodsInfo.setGoodsId(String.valueOf(auditRecord.getId()));
		goodsInfo.setGoodsName("铸造：" + auditRecord.getAssetName());
		goodsInfo.setGoodsNums(1);
		goodsInfo.setGoodsPrice(payOrder.getPayMoney().setScale(2, RoundingMode.HALF_UP));
		goodsInfo.setGoodsType("0");
		return goodsInfo;
	}
}
